Public Module DateTimeExts
 ''' <summary>
 ''' Returns a Calender for the year as a string.
 ''' </summary>
 ''' <param name="dt">The DateTime object to create the year calendar from.</param>
 ''' <returns>Returns a Calender for the year as a string.</returns>
 ''' <remarks></remarks>
 <Runtime.CompilerServices.Extension()> _
 Public Function CalendarOfYear(ByVal dt As DateTime) As String
  Dim CalendarTxt As String = dt.Year.ToString.PadLeft(48) & Environment.NewLine 'Centre the Year in the calendar
  Dim CollectionOfMonthWeekLines(11)() As String
  For MonthNum As Integer = 1 To 12
   ' Get a collection of weeklines for each month
   CollectionOfMonthWeekLines(MonthNum - 1) = New DateTime(dt.Year, MonthNum, 1).WeekLinesOfMonth
  Next
  Dim MostNoOfWeeks As Integer
  For MonthNum = 0 To CollectionOfMonthWeekLines.Count - 1 Step 3
   MostNoOfWeeks = 4
   ' Find which month of the three, which contains the most number of weeks. Set it that number of weeks
   For offset = 0 To 2
    If CollectionOfMonthWeekLines(MonthNum + offset).Count Then MostNoOfWeeks = CollectionOfMonthWeekLines(MonthNum + offset).Count
   Next
   For MonthWeekNo = 0 To MostNoOfWeeks - 1
    For MonthOffset = 0 To 2
     ' If the monthWeekno is eqaul or greather than the number of weeklines in that month add and empty block,
     ' else add that week line to the calendar string.
     ' both are padded to 32 chars
     CalendarTxt &= If(MonthWeekNo >= CollectionOfMonthWeekLines(MonthNum + MonthOffset).Count, _
             " ", _
             CollectionOfMonthWeekLines(MonthNum + MonthOffset)(MonthWeekNo)).PadRight(32)
    Next
    ' End of weeks, so add a new line
    CalendarTxt &= Environment.NewLine
   Next
   ' End of block of months, so add a new line.
   CalendarTxt &= Environment.NewLine
  Next
  ' The calendar in now completed so return it.
  Return CalendarTxt
 End Function

 ''' <summary>
 ''' Returns a Calender for month as a string.
 ''' </summary>
 ''' <param name="dt">TThe DateTime object to create the month calendar from.</param>
 ''' <returns>Returns a Calender for month as a string.</returns>
 ''' <remarks></remarks>
 <Runtime.CompilerServices.Extension()> _
 Public Function CalendarOfMonth(ByVal dt As DateTime) As String
  Return String.Join(Environment.NewLine, WeekLinesOfMonth(dt).ToArray)
 End Function
 ''' <summary>
 ''' Returns an array containing containing a calendar for that month. Each week is a entry.
 ''' </summary>
 ''' <param name="dt">The DateTime object to extract the month week lines from. </param>
 ''' <returns>A string array containing a calendar for that month</returns>
 ''' <remarks>Uses the month value of the DateTime object inputted.
 ''' (0) -> Month Name
 ''' (1) -> Days of the week
 ''' </remarks>

 <Runtime.CompilerServices.Extension()> _
 Public Function WeekLinesOfMonth(ByVal dt As DateTime) As String()
  Dim WeekLines As New List(Of String)
  Dim MonthName As String = dt.ToString("MMMM").ToUpper ' Get month name, then change to uppercase
  WeekLines.Add(MonthName.PadLeft(14 + (MonthName.Length \ 2))) ' Centre Month Name
  WeekLines.Add("MON TUE WED THU FRI SAT SUN") ' Add Weekdays
  Dim DaysInThisMonth As Integer = DateTime.DaysInMonth(dt.Year, dt.Month) ' Get the number of days in month
  Dim CurrentDate As New DateTime(dt.Year, dt.Month, 1) 'Set to first day of month
  Dim WeekStr As String = ""
  For DayNum = 1 To DaysInThisMonth
   WeekStr &= CurrentDate.Day.ToString.PadLeft(3).PadRight(4)
   ' Is the current date a Sunday?
   If CurrentDate.DayOfWeek = DayOfWeek.Sunday Then
    ' Yes, is a Sunday, so pad the left with spaces so the string is 28 chars wide. Then add it to collect of weeklines
    WeekLines.Add(WeekStr.PadLeft(28))
    WeekStr = ""
   End If
   CurrentDate = CurrentDate.AddDays(1) ' Move on to next day.
  Next
  ' Does the weekstr contain any chars, eg last day in the month wasn't a Sunday
  If WeekStr.Count > 0 Then WeekLines.Add(WeekStr.PadRight(28)) 'pad the right with spaces so the string is 28 chars wide. Then add it to collect of weeklines
  Return WeekLines.ToArray
 End Function

End Module